package cn.ahaoweb.drule.core;

import cn.ahaoweb.drule.core.exception.DruleRuleServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Name: 规则服务工厂
 * @Description:
 * @Author: wangzhonghao
 * @Date: 2025/3/7 17:35
 */
public abstract class RuleServiceFactory {

    private static final Logger log = LoggerFactory.getLogger(RuleSessionImpl.class);

    /**
     * 用于存储所有服务实例
     * <pre>
     *     k -> 服务实例的唯一标识符
     *     v -> 服务实例
     * </pre>
     */
    protected Map<String, RuleService> services = new HashMap<>();

    /**
     * 类型选择器集合，注意靠入参对象类型获取服务实例，可能存在多个服务实例共用一个入参而导致某些异常情况。
     * <pre>
     *     k -> 入参类型
     *     v -> 服务实例的唯一标识符
     * </pre>
     */
    protected Map<Class, String> inClassSelectors = new HashMap<>();

    /**
     * 锁集合
     * <pre>
     *     k -> 服务实例的唯一标识符
     *     v -> 服务实例
     * </pre>
     */
    protected Map<String, ReentrantLock> locks = new ConcurrentHashMap<>();

    public boolean addService(RuleService ruleService) {
        return addService(ruleService.getIdentifier(), ruleService);
    }

    public boolean addService(String identifier, RuleService ruleService) {
        return addService(identifier, ruleService, false);
    }

    /**
     * 将规则服务交给调度器管理
     *
     * @param identifier  唯一标识符
     * @param ruleService 服务实例
     * @param absent      是否不存在。当{@link RuleServiceScheduler#services}中不存在时，才加入。
     * @return 是否成功加入调度器管理
     */
    public boolean addService(String identifier, RuleService ruleService, boolean absent) {
        if (identifier == null || ruleService.getIdentifier() == null) {
            throw new NullPointerException("服务实例的唯一标识符为null");
        }
        if (!Objects.equals(identifier, ruleService.getIdentifier())) {
            throw new DruleRuleServiceException("服务实例的唯一标识符错误");
        }
        // 判断是否支持替换旧的服务实例
        if (absent && services.containsKey(identifier)) {
            return false;
        }
        if (ruleService.getKieBase() == null) {
            // 考虑并发安全
            ReentrantLock lock = getLock(identifier);
            try {
                lock.lock();
                if (ruleService.getKieBase() == null) {
                    // 注意：表示ruleService还未初始化，需要初始化
                    ruleService.init();
                }
            } finally {
                lock.unlock();
            }
        }
        services.put(identifier, ruleService);
        FactClassSelector factClassSelector = ruleService.getFactClassSelector();
        if (factClassSelector != null) {
            inClassSelectors.put(factClassSelector.inType(),identifier);
        }
        return true;
    }

    /**
     * 通过 identifier 构造规则服务
     * @param identifier
     * @return
     */
    public RuleService getRuleService(String identifier){
        return services.get(identifier);
    }

    /**
     * 根据给定的标识符获取一个重入锁。
     * <pre>
     *  如果已经存在与给定标识符相关联的锁，则直接返回该锁；
     *  如果不存在，则创建一个新的重入锁，并将其与给定的标识符相关联，然后返回该锁。
     * </pre>
     *
     * @param identifier 用于标识锁的字符串
     * @return 与给定标识符相关联的重入锁
     */
    protected ReentrantLock getLock(String identifier) {
        ReentrantLock lock = locks.get(identifier);
        if (lock == null) {
            synchronized (this) {
                if ((lock = locks.get(identifier)) == null) {
                    lock = new ReentrantLock();
                    locks.put(identifier, lock);
                }
            }
        }
        return lock;
    }

}
